<style lang="scss">
//.cus-insert-input {
//  display: flex;
//  align-items: center;
//}
.cus-insert-preview {
  --input-size: 14px;
  //user-select: none;
  [text-item] {

    position: relative;
    display: inline-block;
    //padding-left: 2px;
    //padding-right: 2px;
    cursor: text;
    vertical-align: middle;
  }
  &__append {
    border: none;
  }
}

.cus-insert-v2__show {
  display: flex;
  align-items: flex-start;
  width: 100%;
}

.cus-insert-v2__dialog {
  .el-dialog__body {
    padding: 0 var(--el-dialog-padding-primary);
  }
}

.cus-insert-preview {
  border: var(--el-border-base);
  height: 6rem; position: relative;
}

.cus-insert-preview {
  &:focus, &.focus {
    border-color: var(--el-color-primary-light-1);

    [text-item][selected]::after {
      background-color: var(--el-color-primary-light-1);
    }
  }

  &.selected {
    [text-item][selected]::after {
      background-color: transparent;
    }
  }

  border-radius: 4px;
}

[text-item]::after {
  //position: absolute;
  //float: right;
  //content: " ";
  //background-color: transparent;
  //letter-spacing: 0.88px;
  //width: 2px;
  //height: 100%;
  //animation: cursor-blinks 1.5s infinite steps(1, start);

  position: absolute;
  //float: right;
  right: 0;
  content: " ";
  background-color: transparent;
  letter-spacing: 0.88px;
  width: 1px;
  height: calc(var(--input-size) * 2);
  animation: cursor-blinks 1.5s infinite steps(1, start);
  /* height: 1em; */
  transform: translateY(-50%);
  top: calc(50% + .1em);
  //line-height: calc(100%);
  /* padding-left: 4px; */
  /* left: 2px; */
  margin-left: 0;
  box-sizing: border-box;
  padding: 3px 0;
  background-clip: content-box
}

[cursor-div] {
  position: absolute;
  //background-color: saddlebrown;
  width: 10px;
  display: inline-block;
  overflow: hidden;
  height: 100%;
  //font-size: 14px;
  white-space: pre;
  pointer-events: none;
  top: 0;
  color: transparent;
  &:focus {
    outline: none;
    &::before {
      //background-color: var(--el-color-primary-light-1);
    }
  }
  &::before {

    position: absolute;
    //float: right;
    left: 0;
    content: " ";
    background-color: transparent;
    letter-spacing: 0.88px;
    width: 1px;
    height: calc(var(--input-size) * 2);
    animation: cursor-blinks 1.5s infinite steps(1, start);
    /* height: 1em; */
    transform: translateY(-50%);
    top: calc(50% + .1em);
    //line-height: calc(100%);
    /* padding-left: 4px; */
    /* left: 2px; */
    margin-left: 0;
    box-sizing: border-box;
    padding: 0;
    background-clip: content-box
  }
}


@keyframes cursor-blinks {
  0% {
    opacity: 1;
    display: block;
  }
  50% {
    opacity: 0;
    display: none;
  }
  100% {
    opacity: 1;
    display: block;
  }
}

.cus-insert-keyboard {
  .el-button {
    margin-bottom: var(--cus-insert-keyboard-mb, 10px);
  }
}

.cus-insert-v2__select-con {
  height: 300px;
  overflow: auto;
  border: 1px solid #e0e0e0;
  border-radius: 2px;
}

.cus-insert-v2__select-textarea {
  border: none;
  .el-textarea__inner {
    height: 100%;
    box-shadow: none;
    border: none;
  }
}
</style>

<template>
  <div  class="cus-insert-v2"   :class="conClass">
    <template v-if="inited">
<!--      {{state.control.funcs}}-->
      <div
      >
        <div class="cus-insert-preview cus-insert-v2__show"
             style="min-height: 1rem; height: auto"
        >
          <div  style="display: inline-block; flex: 1"
                class="cus-insert-html" v-html="runFuncs(state.control.funcs)"></div>
          <el-button  class="cus-insert-v2__append"
                      @click="onInputFocus"><svg t="1646815580839" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3542" width="16" height="16"><path d="M0 0h1024v1024H0z" fill="#FFFFFF" fill-opacity="0" p-id="3543"></path><path d="M880 112c17.673 0 32 14.327 32 32v400c-35.346 0-64-28.654-64-64V176H176v672h304c34.993 0 63.426 28.084 63.991 62.942L544 912H144c-17.673 0-32-14.327-32-32V144c0-17.673 14.327-32 32-32h736z m-38 500v118h118c0 35.346-28.654 64-64 64h-54v54c0 34.993-28.084 63.426-62.942 63.991L778 912V794H660c0-35.346 28.654-64 64-64h54v-54c0-34.993 28.084-63.426 62.942-63.991L842 612zM515.352 245.76c25.519 0 46.82 11.551 61.484 33.466a117.725 117.725 0 0 1 18.432 53.947c0.46 5.774 1.425 17.189 2.899 34.243l0.067 0.78h-65.72c-1.306-12.606-2.234-22.546-2.785-29.82-0.655-6.678-4.67-25.889-14.418-25.889-4.015 0-11.265 6.104-19.335 23.267-7.286 15.377-12.554 33.603-15.767 44.764l-0.167 0.58-1.843 6.268c-0.77 2.717-2.705 10.01-7.512 29.03l-0.092 0.364h84.125c0 35.346-28.654 64-64 64h-35.754l-0.73 2.99c-17.051 70.192-34.102 141.277-50.82 211.488l-3.577 15.032-0.082 0.368-0.082 0.205c-7.219 24.778-31.86 66.577-78.656 67.41l-1.425 0.014h-0.041c-54.439 0-83.153-49.77-91.55-79.221-1.266-4.444-2.684-12.117-4.254-23.02l-0.175-1.224a893.696 893.696 0 0 1-2.198-16.77l-0.095-0.781h65.67c1.21 9.927 2.602 17.633 4.174 23.116 0.082 0.287 10.24 31.213 28.469 31.213 7.93 0 14.42-12.306 16.868-19.161l0.09-0.255 2.58-10.732c5.696-23.914 20.492-86.047 35.524-148.531l1.142-4.746 1.142-4.743c2.965-12.313 5.922-24.566 8.802-36.467l0.784-3.236 0.72-2.949H303.72c0-35.346 28.654-64 64-64h35.164c6.416-25.866 10.558-42.15 12.384-48.379l0.054-0.185 1.72-5.858c5.285-18.31 13.272-46.041 27.61-70.045 18.473-30.885 42.23-46.533 70.7-46.533zM694.17 516.456l0.872 0.6L639.064 597l55.978 79.944-0.872 0.6c-28.878 19.53-68.192 12.347-88.263-16.317L600 652.789l-5.907 8.438c-20.071 28.664-59.385 35.848-88.263 16.317l-0.872-0.6L560.935 597l-55.977-79.944 0.872-0.6c28.878-19.53 68.192-12.347 88.263 16.317L600 541.21l5.907-8.437c20.071-28.664 59.385-35.848 88.263-16.317z" fill="#666666" p-id="3544"></path></svg></el-button>
        </div>

        <div>
          <el-button size="small" @click="exportFile">导出</el-button>
          <el-button size="small" @click="importFile">导入</el-button>
        </div>
      </div>

      <el-dialog
          v-model="state.drawer"
          title="公式输入"
          @opened="onModalOpened"
          @closed="onModalClosed"
          :close-on-click-modal="false"
          :append-to-body="true"
          modal-class="cus-insert-v2__dialog"
      >
        <div
            :id="hid"
            class="cus-insert-keyboard" tabindex="-1"
            @keydown="onPopupkeyup">
          <div
              :id="tid"
              class="a-space-mb-10 cus-insert-preview"
              style="height: 6rem"
              :class="{'focus': state.drawer || state.focused,}"
              tabindex="-1"
              @focus="onFocus"
              @blur="onConBlur"
          >
            <div
                style="flex: 1"
                @mouseup="onMainMouseUp"
                @mousedown="onMouseDown"
                @mousemove="onMouseMove"
            >
              <div content style="display: inline-block"
                   class="cus-insert-html" v-html="runFuncs(state.control.funcs)"></div>
              <span :id="cursorID"  cursor-div contenteditable="true"
                    style="display: inline-block;"
                    @focus="onCusorfocus"
                    @blur="onCusorblur"
                    @compositionstart="onCursorcompositionstart"
                    @compositionend="onCursorcompositionend"
                    @keyup="onCursorChange"
                    @keydown="onCursorkeydown"
              ></span>
            </div>
          </div>

          <el-row class="a-space-mb-10">
            <div style="flex: 1">&nbsp;</div>
            <el-button size="small" @click="funTools.checkValidity">检查合法性</el-button>
          </el-row>
          <el-row class="a-space-mb-10"
                  :gutter="10">
            <el-col :span="6" >
              <div v-if="toolState.insertedVars && toolState.insertedVars.length > 0">
                <div class="a-space-mb-10">字段值：</div>
                <div class="cus-insert-v2__select-con">
                  <template v-for="item in toolState.insertedVars">
                    <el-popover trigger="hover" width="450" placement="top">
                      <div v-html="getVarDOC(item)"></div>
                      <template #reference>
                        <template v-if="isArray(item)">
                          <el-button @click="insertTVars(item)"><span v-html="item[0]"></span></el-button>
                        </template>
                        <template v-else>
                          <el-button @click="insertText(`${item}`, 'xy-text', '')"><span v-html="item"></span></el-button>
                        </template>
                      </template>
                    </el-popover>
                  </template>
                </div>
              </div>

              <div v-if="toolState.insertedVarsV2 && toolState.insertedVarsV2.length > 0">
                <div class="a-space-mb-10">字段名：</div>
                <div class="cus-insert-v2__select-con">
                  <template v-for="item in toolState.insertedVarsV2">
                    <el-popover trigger="hover" width="450" placement="top">
                      <div v-html="getVarDOC(item)"></div>
                      <template #reference>
                        <template v-if="isArray(item)">
                          <el-button @click="insertTVars(item)"><span v-html="item[0]"></span></el-button>
                        </template>
                        <template v-else>
                          <el-button @click="insertText(`${item}`, 'xy-text', '')"><span v-html="item"></span></el-button>
                        </template>
                      </template>
                    </el-popover>
                  </template>
                </div>
              </div>

            </el-col>

            <el-col :span="6">
              <div> <div class="a-space-mb-10">变量：</div></div>
              <div class="cus-insert-v2__select-con">
                <el-tree default-expand-all :data="varTools.state.data" :props="varTools.defaultProps"
                         @node-click="varTools.handleNodeClick" >
                  <template #default="{ node, data }">
                    <div style="height: 100%; width: 100%; line-height: 26px"
                    @dblclick="varTools.handleInsert(data, node)">{{data.label}}</div>
                  </template>
                </el-tree>
              </div>
            </el-col>
            <el-col :span="6">
              <div> <div class="a-space-mb-10"> 函数：</div>
<!--                <template v-for="item in insertedFun">-->
<!--                  <el-popover trigger="hover" width="450" placement="top">-->
<!--                    <div v-html="getFunDOC(item)"></div>-->
<!--                    <template #reference><el-button-->
<!--                        @click="insertFun(item)"><span v-html="item"></span></el-button></template>-->
<!--                  </el-popover>-->
<!--                </template>-->
                <div class="cus-insert-v2__select-con">
                  <el-tree default-expand-all :data="funTools.state.data" :props="funTools.defaultProps"
                        @node-click="funTools.handleNodeClick"
                           >
                    <template #default="{ node, data }">
                      <div style="height: 100%; width: 100%; line-height: 26px"
                           @dblclick="funTools.handleInsert(data, node)">{{data.label}}</div>
                    </template>
                  </el-tree>
                </div>
              </div>
            </el-col>
            <el-col :span="6">
              <div> <div class="a-space-mb-10"> 公式说明：</div>
                <div class="cus-insert-v2__select-con">
                  <el-input class="cus-insert-v2__select-textarea"
                            readonly
                            style="height: 100%;" type="textarea" v-model="funTools.state.curNotice"></el-input>
                </div>
              </div>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="24">
              <div>
                <el-button @click="backStep">退格</el-button>
                <el-button @click="insertFun('')">插入括号</el-button>
                <el-button @click="insertQute('')">插入引号</el-button>
<!--                <el-button @click="insertEmoji('fuck')">插入<z-emoji  face="fuck"></z-emoji></el-button>-->
                <template v-for="item in insertedText">
                  <el-button @click="insertText(`${item}`)"><span v-html="item"></span></el-button>
                </template>
              </div>
            </el-col>
          </el-row>

        </div>
      </el-dialog>


    </template>
  </div>


</template>

<script>
import {CustomRenderControlMixin, defineCustomRender} from "@/plugins/form-render/utils/index.js";
import {inject, nextTick, onMounted, reactive, toRaw} from "vue";
import {evalStr} from "@/plugins/form-render/utils/evalGlo";

/**
 *
 * @param props
 * @param ctx
 * @param options
 * @returns {{handleNodeClick: handleNodeClick, defaultProps: {children: string, label: string}, state: UnwrapNestedRefs<{data: [{children: [{label: string, value: string},{label: string, value: string}], label: string}]}>}}
 */
function buildVarTools(props, ctx, options) {
  let state = reactive({
    data: [
      {
        label: '用户信息',
        children: [
          {
            label: '部门名',
            value: '$G.userinfo.deptName',
          },
          {
            label: '真实姓名',
            value: '$G.userinfo.realname',
          },
        ],
      },
    ]
  })

  let defaultProps = {
    children: 'children',
    label: 'label',
  }

  function handleNodeClick(data, node, e) {
    if (node.isLeaf) {
      // console.log('handleNodeClick', data, node)
      // options.insertText(data.value, 'xy-text', 'data-global-var')
    }
  }

  function getLabel(node, opt = {label: ''}) {
    // console.log(node)
    if (node.parent) {
      if (Array.isArray(node.parent.data)) {
        // opt.label = node.parent.data[0].label + '-' + opt.label
      } else {
        opt.label = node.parent.data.label + '-' + opt.label
        getLabel(node.parent, opt)
      }
    }
  }

  function handleInsert(data, node) {
    if (node.isLeaf) {
      // options.insertText(data.value, 'xy-text', 'data-global-var')
      let opt = {label: ''}
       getLabel(node,opt)
      // console.log(opt)
      options.insertText(opt.label + data.label, 'xy-text', `val="${data.value}" data-global-var`)
    }
  }

  return {
    defaultProps,
    handleInsert,
    handleNodeClick,
    state
  }
}

/**
 *
 * @param props
 * @param ctx
 * @param options
 * @returns {{handleNodeClick: handleNodeClick, defaultProps: {children: string, label: string}, state: UnwrapNestedRefs<{data: [{children: [{label: string, value: string},{label: string, value: string}], label: string}]}>}}
 */
function buildFunTools(props, ctx, options) {
  let state = reactive({
    data: [

    ],
    curNotice: '',
    isAppend: false
  })

  let defaultProps = {
    children: 'children',
    label: 'label',
  }

  function handleNodeClick(data, node) {
    if (node.isLeaf) {
      // console.log('handleNodeClick', data, node)
      state.curNotice = data.notice
    }
  }

  function handleInsert(data, node) {
    if (node.isLeaf) {
      options.insertFun(data.value)
    }
  }

  /**
   * 设置函数
   * @param v
   * @param useLib
   */
  function setFuns(v = [], {useLib = true} = {}) {
    // console.log('r', r)
    let arr = [
    ]
    if (useLib) {
      arr = [
        {
          label: '常用函数',
          children: [
            ...globalThis.evalGOGetFuns('常用函数')
          ],
        },
      ]
    }

    state.data = arr.concat(v)
  }

  function checkValidity() {
    let clonedValue = options.getClonedValue()
    let str = clonedValue.textContent
    // console.log(clonedValue.textContent)
    try {
      let ctx = {
        M() {},
        $G: {
          userinfo: {}
        }
      }
      state.data.forEach(groups => {
        if (Array.isArray(groups.children)) {
          groups.children.forEach(fun => {
            ctx[fun.label] = function () {
            }
          })
        }
      })
      evalStr(str, ctx)
      globalThis.ElMessage.success('检测成功');
    } catch (e) {
      // globalThis.ElMessage.error('检测失败');
      globalThis.ElementPlus.ElMessageBox({title: '检测失败', message: e})
      console.log(e, str)
    }
  }

  return {
    defaultProps,
    checkValidity,
    setFuns,
    handleInsert,
    handleNodeClick,
    state
  }
}

export default {
  name: 'CusInsertV2',
  components: { },
  mixins: [
    CustomRenderControlMixin
  ],
  props: {
    docEnums: {
      type: String,
      default: 'ROOT_STATE("tools.toolDocs")'
    },
    beforeModalOpened: null,
    onModalClosed: null,
    conClass: ''
    // modelValue: null
  },
  setup(props, ctx) {

    let START_INSERT_ID = 'START_INSERT_ID__' + ZY.rid()
    let {part_key} = props.defs;
    let obj;
    let JSON5 = ZY.JSON5;
    let lastIndex = 0
    let hid = 'htm' + ZY.rid(6).toLowerCase()
    let tid = 'htm' + ZY.rid(6).toLowerCase()
    let cursorID = 'cursor' +  ZY.rid(6).toLowerCase()

    let mouse_down_focused = false

    let widgetConfig =  props?.ui?.widgetConfig ?? {}

    let toolState = reactive({
      insertedVars: [],
      insertedVarsV2: []
    })

    let codes = [
      'a',
      'b',
      'c',
      'd',
      'e',
      'f',
      'g',
      'h',
      'i',
      'j',
      'k',
      'l',
      'm',
      'n',
      'o',
      'p',
      'q',
      'r',
      's',
      't',
      'u',
      'v',
      'w',
      'x',
      'y',
      'z',
    ]

    codes = codes.concat(
        codes.map(v => {
          return v.toUpperCase()
        })
    )

    let insertedText = [
        '+', '-', '*', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '[', ']', '.',
        '_',
        '=',
      '(',
      ')',
      '{',
      '}',
      ';',
      ',',
      '\'',
 ...codes
    ]

    // console.log(widgetConfig.insText)

    if (Array.isArray(widgetConfig.insText)) {
      insertedText = insertedText.concat(widgetConfig.insText)
    }

    let insertedFun = [
        // 'Math'
    ]

    if (Array.isArray(widgetConfig.insFun)) {
      insertedFun = insertedFun.concat(widgetConfig.insFun)
    }


    let insertedVars = [

    ]

    if (Array.isArray(widgetConfig.insVars)) {
      insertedVars = insertedVars.concat(widgetConfig.insVars)
    }

    toolState.insertedVars = insertedVars

    let inited = false

    let { data, methods, listeners, init, modelUpdate, instanse, widgetConfig2 } = defineCustomRender(props, ctx, {
      handleValueInit(newVal, from) {
        if (!newVal) {
          newVal = '{}'
          // return newVal
        }

        console.log('cusinsert v2 handleValueInit', newVal, typeof  newVal)
        if (newVal) {
          try {
            obj = JSON5.parse(newVal)
            if (typeof obj === 'string') {
              obj = JSON5.parse(obj)
            }

            // console.log(obj)

            if (!inited) {
              if (obj && obj.funcs) {
                inited = true
              }
              lastIndex = toRaw( obj.funcs).length
              // console.log(lastIndex)
              nextTick(() => {
                if (state.value.funcs) {
                  state.control.funcs =  toRaw( state.value.funcs)
                }
                // setTimeout(() => {
                //   setCursor(
                //       lastIndex,
                //       'init',
                //       1,
                //       {
                //         focus: false
                //       }
                //   )
                // }, 100)
              })
            }


            return obj
          } catch (e) {
            console.error(e)
          }
        }
        return {}
      }
    })
    let state = data({
      value: {},
      control: {},
      drawer: false,
      focused: false,
      selected: false,
      pinyin: '',
      parsedList: [],
      parsedText: [],
      str: ''
    })
    init(props)

    // console.log(widgetConfig)

    function onChange() {
      let clonedValue = JSON5.parse(JSON5.stringify(state.control))
      // console.log(clonedValue)
      // clonedValue = toRaw(state.control)
      // Reflect.deleteProperty(clonedValue, 'control')
      let dom = document.querySelector(`#${hid} [content]`)
      if (!dom) {
        return;
      }
      let child = dom.children
      let content = ''
      if (child.length > 0) {
        Array.of(...child).forEach(item => {
          // console.log(item)
          if (item.hasAttribute('val')) {
            content = content + item.getAttribute('val')
          } else {
            content = content + item.textContent
          }
        })
      }
      // console.log(child, content)
      // let content = document.querySelector(`#${hid} [content]`)?.textContent ?? ''
      clonedValue.textContent = content.trim()
      let str =JSON5.stringify(clonedValue)
      state.str = clonedValue.textContent
      methods.onChange(str)
    }

    function getCachedClonedValue() {
      let clonedValue = JSON5.parse(JSON5.stringify(state.control))
      return clonedValue
    }


    function getClonedValue() {
      let clonedValue = JSON5.parse(JSON5.stringify(state.control))
      // console.log(clonedValue)
      // clonedValue = toRaw(state.control)
      // Reflect.deleteProperty(clonedValue, 'control')
      let dom = document.querySelector(`#${hid} [content]`)
      if (!dom) {
        return;
      }
      let child = dom.children
      let content = ''
      if (child.length > 0) {
        Array.of(...child).forEach(item => {
          // console.log(item)
          if (item.hasAttribute('val')) {
            content = content + item.getAttribute('val')
          } else {
            content = content + item.textContent
          }
        })
      }
      // console.log(child, content)
      // let content = document.querySelector(`#${hid} [content]`)?.textContent ?? ''
      clonedValue.textContent = content.trim()
      return clonedValue
    }

    function getText() {
      let clonedValue = getClonedValue()
      if (typeof clonedValue === 'undefined') {
        clonedValue = getCachedClonedValue()
      }
      // console.log(clonedValue)
      let str =JSON5.stringify(clonedValue)
      return str
    }

    function save() {
      onChange()
    }

    function onBlur() {
      onChange()
    }

    function resetFuncs() {
      if (! state.control.funcs) {
        state.control.funcs = []
      }
    }

    function getIndex(added = 1) {
      let trueIndex = lastIndex - 1
      if (trueIndex === -1) {
        return 0
      }
      if (trueIndex < -1) {
        return state.control.funcs.length
      }
      return trueIndex + added
    }

    function insertChange(addLength) {
      // console.log('sdsds', length)
      setTimeout(() => {
        let length = state.control.funcs.length
        setCursor(length - 1, 'add', addLength);
        onChange()
      }, 30)
    }
    function insertChangev2(addLength) {
      // console.log('sdsds', length)
      // let length = state.control.funcs.length
      setTimeout(() => {
        setCursor(112121, 'add', addLength);
        setTimeout(() => {
          onChange()
        }, 100)
      }, 30)
    }

    function insertFun(name) {
      resetFuncs()
      let index  = getIndex()
      state.control.funcs.splice(index, 0, [
          'return \`${VAL}<xy-text text-item level="${INDEX}">'+name+'(</xy-text>\`',
      ])

      state.control.funcs.splice(index + 1, 0, [
        'return \`${VAL}<xy-text text-item level="${INDEX}">)</xy-text>\`',
      ])
      insertChange()
    }

    function insertQute(name) {
      resetFuncs()
      let index  = getIndex()
      state.control.funcs.splice(index, 0, [
        'return \`${VAL}<xy-text text-item level="${INDEX}">\'</xy-text>\`',
      ])

      state.control.funcs.splice(index + 1, 0, [
        'return \`${VAL}<xy-text text-item level="${INDEX}">\'</xy-text>\`',
      ])
      insertChange()
    }

    function insertText(v, tag = 'xy-text', attr = '') {
      resetFuncs()
      let index  = getIndex()
      // console.log(index)
      state.control.funcs.splice(index, 0, [ 'return \`${VAL}<'+tag+' text-item level="${INDEX}" '+attr+' >'+v+'</'+tag+'>\`'])

      insertChange()
    }


    function isArray(v) {
      return Array.isArray(v)
    }

    function insertTVars(item) {
      insertTexts([item[0]], item[1], item[2])
    }

    function insertTexts(texts = [], tag = 'xy-text', attr = '') {
      if (Array.isArray(texts) && texts.length > 0) {
        resetFuncs()
        let index  = getIndex()
        let textCommands = texts.map(v => {
          return ['return \`${VAL}<'+tag+' text-item level="${INDEX}" '+attr+' >'+v+'</'+tag+'>\`']
        })
        // console.log(state.control.funcs, textCommands)
        state.control.funcs.splice(index, 0, ...textCommands)

        insertChangev2(textCommands.length)
      }
    }


    function insertEmoji() {
      // <z-emoji zoom=".7" face="fuck">&nbsp;</z-emoji>
      insertText('', 'z-emoji', 'zoom=".7" face="fuck"')
    }

    function runFuncs(funcs) {
      let trueFuns = [ ['return `<xy-text text-item level="0">&nbsp;</xy-text>`']]
      if (Array.isArray(funcs)) {
        trueFuns = trueFuns.concat(
            funcs
        )
        // }
      // return ''
      }

      let runFuns = trueFuns.map((v, index) => {
        return new Function('VAL', `let INDEX = ${index}; ` + v[0])
      })

      // console.log(trueFuns)

      // if (trueFuns.length > 0) {

      let ret = ZY.R.pipe.apply(null, runFuns)('')
      // console.log(trueFuns, ret)
      return ret

      // return ''
    }

    function backCursor(cb) {
      let Index = lastIndex - 1
      if (Index < -1) {
        Index = -1
      }
      // console.log('backCursor', Index)
      setTimeout(() => {
        setCursor(
            Index,
            'remove'
        )
        if (cb) {
          cb()
        }
      }, 30)
    }

    function nextCursor(cb) {
      let Index = lastIndex + 1
      // if (Index >    state.control.funcs.length - 1) {
      //   Index =    state.control.funcs.length - 1
      // }

      // console.log('nextCursor', Index)

      if (Index <  state.control.funcs.length + 1) {
        setTimeout(() => {
          setCursor(
              Index,
              'next'
          )
          if (cb) {
            cb()
          }
        }, 30)
      }
    }

    function backStep() {
      state.control.funcs.splice(lastIndex - 1, 1)
      // console.log(state.control.funcs)
      // let Index = lastIndex - 1
      // if (Index < -1) {
      //   Index = -1
      // }
      // setTimeout(() => {
      //   setCursor(
      //       Index,
      //       'remove'
      //   )
      //   onChange()
      // }, 30)
      backCursor(function () {
        onChange()
      })
    }

    function setCursor(index, type, addLength = 1, {focus = true} = {}) {
      let INDEX = parseInt(index)

      let last = document.querySelector(`#${hid} [level="${lastIndex}"]`)
      if (last) {
        last.removeAttribute('selected')
      }
      // console.log(lastIndex)
      if (type === 'add') {
        lastIndex = lastIndex + addLength
      } else {
        lastIndex = INDEX
      }
      // console.log(lastIndex)
      let current = document.querySelector(`#${hid} [level="${lastIndex}"]`)
      // console.log(current)
      if (current) {
        current.setAttribute('selected', 1)
        // console.dir(current.offsetLeft + current.clientWidth)

        let newLeft = current.offsetLeft + current.clientWidth
        let cursor = document.getElementById(cursorID)
        cursor.style.left = newLeft + 'px'
        if (focus) {
          cursor.focus()
        }
      }
    }

    function setFirstCursor() {
      setCursor(
          0,
          'index'
      )
    }

    function setLastCursor() {
      setCursor(
          state.control.funcs.length,
          'index'
      )
    }

    /**
     *
     */
    function initLastCursor() {
      if (Array.isArray(state.control.funcs)) {
        setLastCursor()
      } else {
        setFirstCursor()
      }
    }

    function onClick(e) {
      // console.log('onClick', e.target)
      if  (e.target.hasAttribute('text-item')) {
        setCursor(
            e.target.getAttribute('level'),
            'index'
        )
      }
    }

    let lifeTimes = {
      onReady() {
      }
    }

    function onValueChanged() {
      // console.log('  onValueInited', state)
    }


    function handleKeyUP(e, options = {}) {
      e.preventDefault();
      e.stopPropagation();
      console.log(e)
      if (e.key === 'Backspace') {
        backStep()
      } else  if (insertedText.includes(e.key)) {
        if (options.onText) {
          options.onText(e.key, e)
        } else {
          insertText(e.key)
        }
      } else if (e.key === 'ArrowLeft') {
        // console.log('ArrowLeft')
        backCursor()
      } else if (e.key === 'ArrowRight') {
        // console.log('ArrowRight')
        nextCursor()
      } else if (e.key === 'ArrowUp') {
        // console.log('ArrowUp')
        setFirstCursor()
      } else if (e.key === 'ArrowDown') {
        setLastCursor()
      }
    }


    function onInsertkeyup(e) {
      handleKeyUP(e)
    }

    function prevent(e) {
      e.preventDefault();
      e.stopPropagation();
    }

    function onPopupkeyup(e, options= {}) {

      // if (e.key === 'Backspace') {
      //   prevent(e);
      //   backStep()
      // } else  if (insertedText.includes(e.key)) {
      //   prevent(e);
      //   if (options && options.onText) {
      //     options.onText(e.key, e)
      //   } else {
      //     insertText(e.key)
      //   }
      // } else if (e.key === 'ArrowLeft') {
      //   // console.log('ArrowLeft')
      //   prevent(e);
      //   backCursor()
      // } else if (e.key === 'ArrowRight') {
      //   // console.log('ArrowRight')
      //   prevent(e);
      //   nextCursor()
      // } else if (e.key === 'ArrowUp') {
      //   // console.log('ArrowUp')
      //   prevent(e);
      //   setFirstCursor()
      // } else if (e.key === 'ArrowDown') {
      //   prevent(e);
      //   setLastCursor()
      // }

      // handleKeyUP(e)
    }

    function onInputFocus(e) {
      // console.log('onFocus', e)
      e.stopPropagation();
      // if (!document.querySelector('.cus-insert-input.focus')) {
      //   // console.log(widgetConfig)
      //   // if (widgetConfig.imeVars) {
      //   //   let imeInsVars = ZY_EXT.eval5(widgetConfig.imeVars, {
      //   //     globalThis,
      //   //     props
      //   //   })
      //   //   console.log(props)
      //   //   if (Array.isArray(imeInsVars)) {
      //   //     toolState.insertedVars = imeInsVars
      //   //   }
      //   // }
      //   state.drawer = true
      //   state.pingyin = ''
      //   state.parsedList = [[], '']
      //   state.parsedText = []
      // }
      state.drawer = true
    }

    /**
     * 导出
     */
    async function exportFile() {
      let text = getText()
      // console.log(text)
      let inputTplName = await getApp().confirmMessageBox({
        label: '文件名',
        options: {
          showCancelButton: false
        }
      })
      let fileName = ( inputTplName ?? `cusinsertv2__${props.field_uuid}_`)

      if (globalThis.useElectronSave) {
        let f = ZY2.getDownloadFileName('', fileName) + '.json5'
        globalThis.useElectronSave(text, {fileName: f})
      } else {
        await ZY_EXT.saveStrUseFS(text, {
          extensions: ['.json5'],
          fileName: fileName + '.json5',
          type: 'text/plain',
        })
      }
    }

    /**
     * 导入
     */
    async function importFile() {
      let obj = await ZY2.fileOpenJSON5()
      if (obj) {
        // console.log(obj)
        state.control = obj
      }
    }

    function onInputBlur(e) {
      // console.log('onBlur', e)
      // state.drawer = false
    }

    function onModalClosed() {
      document.getElementById(hid)?.focus()
      document.getElementById(hid).removeEventListener('click', onClick)
      // console.log(document.getElementById(hid))
      if (props.onModalClosed) {
        props.onModalClosed({
          funTools,
          toolState,
          getText
        })
      }
      let textObj = getText()
      let str =JSON5.stringify(textObj)
      // ctx.emit('modelUpdate', str)
      modelUpdate(str)
      ctx.emit('modalClosed')
    }


    function onModalOpened() {
      if (props.beforeModalOpened) {
        props.beforeModalOpened({
          funTools,
          toolState
        })
      }

      // console.log(widgetConfig)
      if (widgetConfig.imeVars) {
        // let ZDragxmlInstance = inject(widgetConfig.insVars)
        // let insVars = ZDragxmlInstance.getInsVars()
        // toolState.insertedVars = widgetConfig.getInsVars()
        let ret = ZY_EXT.eval5(widgetConfig.imeVars, {
          globalThis,
          props
        })
        // console.log(ret)
        if (Array.isArray(ret)) {
          toolState.insertedVars = ret
        }
      }
      setTimeout(() => {
        let hidDOM = document.getElementById(hid)
        // console.log(hidDOM)
        if (hidDOM) {
          // hidDOM.focus()
          hidDOM.addEventListener('click', onClick)
        }
        // if (cursorID) {
        //   let tidDOM =  document.getElementById(cursorID)
        //   // console.log(tidDOM)
        //   tidDOM.focus()
        // }
        initLastCursor()
        // initLastCursor()
        // insertText(START_INSERT_ID)
      }, 100)
    }

    function onFocus(e) {
      // if (document.querySelector('.cus-insert-input.focus')) {
      //   Array.of(...document.querySelectorAll('.cus-insert-input:not(.focus)')).forEach(item => {
      //     item.blur()
      //   })
      // }
      // console.log(document.getElementById(cursorID))
      document.getElementById(cursorID)?.focus()
    }

    function onConBlur() {
      // state.focused = false
      // document.getElementById(cursorID)?.blur()
    }



    let moveStart = 0
    let moveInstanse = 0
    let MOVE_DETECT = 60

    function onMainMouseUp(e) {
      // console.log('onMainMouseUp', e)
      // if (e.key === 'Control') {
      // //
      // } else {
      //   document.getElementById(cursorID)?.focus()
      // }
      // if (moveInstanse < MOVE_DETECT) {
      //   document.getElementById(cursorID)?.focus()
      // }
      state.selected = false
      mouse_down_focused = false
    }
    function onMouseDown(e) {
      moveStart = e.clientX
      mouse_down_focused = true
    }
    function onMouseMove(e) {
      // console.log('moveInstanse', mouse_down_focused, moveInstanse, e.clientX)
      if (mouse_down_focused) {
        // moveInstanse =  Math.abs(e.clientX-moveStart)
        // if (moveInstanse > MOVE_DETECT) {
        //   document.getElementById(cursorID)?.blur()
        //   state.selected = true
        // }
        state.selected = true
      }
    }

    let toolDocs = []

    function getFunDOC(funName = '') {
      if (toolDocs.length < 1) {
        toolDocs = instanse.ctx.dxValueTemplate(props.docEnums, [])
      }
      let finded = toolDocs.find(v => v.label === funName)

      if (finded) {
        let str = finded.value
        if (ZY.lodash.isFunction(finded.value)) {
          str = finded.value()
        }
        return ZY_EXT.marked(str ?? '')
      }

      return '空'
    }

    function getVarDOC(item = []) {
      // console.log(item)
      if (Array.isArray(item) && item[3]) {
        let obj = item[3]
        if (obj.doc) {
          return obj.doc
        }
      }
      return '空'
    }

    let isPinyin = false
    let isPinyinInsert = false
    let pinyinLock = false
    let change_ime_temped_text = ''

    function onCursorChange(e) {
      e.stopPropagation()
      e.preventDefault()
      // console.log('isPinyin', isPinyin)
      if (moveInstanse > MOVE_DETECT - 1) {
        return;
      }

      if (isPinyin) {

      } else {
        // console.log('sdsdsdsds', e)

      }
      if (e.code === 'Space') {
        console.log('输入法保存', isPinyinInsert, e.target.innerText)
        if (isPinyinInsert) {
          pinyinLock = true
          let text = e.target.innerText?.replace(change_ime_temped_text, '') ?? ''
          console.log(text)
          let textArr = [...text]
          insertTexts(textArr)
          e.target.innerText = ''

          isPinyinInsert = false;
          setTimeout(() =>{
            pinyinLock = false
          }, 30)
        } else {
          if (!pinyinLock) {

            insertText('&nbsp;')
          }
        }
      }
      else if (e.code === 'Enter') {
        // console.log('Enterbaocun')
        let textArr = [...e.target.innerText]
        insertTexts(textArr)
        e.target.innerText = ''
      }
      else if (e.code === 'Backspace') {
        backStep()
      }
      else if (e.code === 'ShiftLeft') {
        // console.log('ShiftLeft', e.target.innerText)
        change_ime_temped_text =  e.target.innerText
      }
      else if (e.key === 'ArrowLeft') {
        // console.log('ArrowLeft')
        backCursor()
      } else if (e.key === 'ArrowRight') {
        // console.log('ArrowRight')
        nextCursor()
      } else if (e.key === 'ArrowUp') {
        // console.log('ArrowUp')
        setFirstCursor()
      } else if (e.key === 'ArrowDown') {
        setLastCursor()
      }
      else {
        // console.log('onCursorChange', e)
      }

      // isPinyin = false
    }

    function onCursorkeydown(e) {
      if (!isPinyin) {
        if (insertedText.includes(e.key)) {

          insertTexts([e.key])
          e.target.innerText = ''
        }
      }
    }

    function onCusorfocus() {
      state.focused = true
    }

    function onCusorblur() {
      state.focused = false
    }

    function onCursorcompositionstart(e) {
      // console.log('onCursorcompositionstart')
      isPinyin = true
      isPinyinInsert = true
    }

    function onCursorcompositionend(e) {
      // console.log('onCursorcompositionend')
      isPinyin = false
    }

    let varTools = buildVarTools(props, ctx, {
      insertText
    })

    let funTools = buildFunTools(props, ctx, {
      insertText,
      getClonedValue,
      insertFun
    })


    onMounted(() => {
      // console.log('cus insert v2', widgetConfig2)
      if (widgetConfig2.useFuns) {
        funTools.setFuns()
      }
    })

    return {
      state,
      widgetConfig,
      getFunDOC,
      getVarDOC,
      onChange,
      cursorID,
      varTools,
      funTools,
      insertFun,
      insertText,
      tid,
      insertQute,
      isArray,
      // selectCnText,
      onCursorcompositionstart,
      onCursorcompositionend,
      onCursorChange,
      onCursorkeydown,
      onCusorfocus,
      onCusorblur,
      insertEmoji,
      backStep,
      hid,
      lifeTimes,
      insertedText,
      insertedFun,
      insertTVars,
      onFocus,
      onMainMouseUp,
      onMouseDown,
      onMouseMove,
      insertedVars,
      toolState,
      exportFile,
      importFile,
      onValueChanged,
      onModalOpened,
      methods,
      onConBlur,
      onModalClosed,
      onInputFocus,
      onInputBlur,
      onBlur,
      onInsertkeyup,
      onPopupkeyup,
      runFuncs,
      save,
      listeners,
    }
  },
}
</script>

